package com.echo.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.qifan.infrastructure.common.model.R;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 * 全局响应拦截器，用于统一封装接口的返回数据。
 */
@RestControllerAdvice(basePackages = "com.echo.aichat") // 只拦截指定包路径下的控制器
@Slf4j // 添加日志支持
@AllArgsConstructor // 自动生成包含所有参数的构造器
public class ResponseInterceptor implements ResponseBodyAdvice<Object> {

    private final ObjectMapper objectMapper; // 用于处理 JSON 转换的工具

    /**
     * 确定是否需要拦截返回值
     *
     * @param returnType      返回值类型
     * @param converterType   转换器类型
     * @return 是否支持拦截，返回 true 表示所有返回值都会被拦截
     */
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true; // 拦截所有返回值
    }

    /**
     * 在返回值写入响应体之前对其进行处理
     *
     * @param body               控制器方法返回的原始数据
     * @param returnType         返回值的类型信息
     * @param selectedContentType 响应内容类型
     * @param selectedConverterType 选择的消息转换器类型
     * @param request            当前请求对象
     * @param response           当前响应对象
     * @return 处理后的响应数据
     */
    @SneakyThrows // 处理受检异常，不需要显式捕获
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType,
                                  MediaType selectedContentType, Class selectedConverterType,
                                  ServerHttpRequest request, ServerHttpResponse response) {
        // 如果返回值是字节数组（如文件下载等场景），直接返回
        if (body instanceof byte[]) {
            return body;
        }
        // 如果返回值已经是封装好的 R 对象，直接返回，无需再次封装
        if (body instanceof R) {
            return body;
        }
        // 如果返回值是字符串类型（String），需要特殊处理以防止消息转换器问题
        if (body instanceof String) {
            // 设置响应头的内容类型为 JSON
            response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
            // 将字符串包装为 R 对象后再转换为 JSON 字符串返回
            return objectMapper.writeValueAsString(R.ok(body));
        }
        // 如果返回值是 null，直接返回 null
        if (body == null) {
            return null;
        }
        // 对其他类型的返回值进行统一封装，并打印日志
        log.debug("响应结果：{}", body); // 记录返回值日志，便于调试
        return R.ok(body); // 将返回值封装为 R 对象
    }
}
